/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package ro.unibuc.hobbygroups.dao;

import java.awt.Container;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.RenderingHints;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.List;

import org.springframework.beans.factory.annotation.Required;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import ro.unibuc.hobbygroups.domain.Picture;
import ro.unibuc.hobbygroups.exception.HobbyGroupsException;

import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGEncodeParam;
import com.sun.image.codec.jpeg.JPEGImageEncoder;

/**
 * @author Root
 */
public class PicturesDAOImpl extends HibernateDaoSupport implements PicturesDAO {

	private File storagePathFolder;

	public Picture find(Long id) {
		return getHibernateTemplate().get(Picture.class, id);
	}

	public List<Picture> findAll() {
		return getHibernateTemplate().loadAll(Picture.class);
	}

	public Long create(Picture pic, byte[] content) {
		try {
			// Save on Disk
			
			File photo = File.createTempFile("pic", "", storagePathFolder);
			writeFile(photo, content);

			// Update pic object
			pic.setStoragePath(photo.getAbsolutePath());
			
			// also save a thumb version of the file
			// create the file
			File thumb = new File(getThumbPath(photo.getAbsolutePath()));
			thumb.createNewFile();
			
			createThumbnail(photo.getAbsolutePath(), thumb.getAbsolutePath(), 120, 120);
			
			// Save in database
			return (Long) getHibernateTemplate().save(pic);

		} catch (Exception e) {
			throw new HobbyGroupsException(e);
		} 
	}

	public byte[] getPictureContent(Picture pic) {
		try {
			return readFile(pic.getStoragePath());
		} catch (IOException e) {
			throw new HobbyGroupsException(e);
		}
	}

	public byte[] getThumbContent(Picture pic) {
		try {
			return readFile(getThumbPath(pic.getStoragePath()));
		} catch (IOException e) {
			throw new HobbyGroupsException(e);
		}
	}

	@Required
	public void setStoragePathFolder(String storagePath) {
		storagePathFolder = new File(storagePath);

		// Attempt to create the folder on disk.
		if (storagePathFolder.exists()) {
			boolean deleted = deleteDir(storagePathFolder);
			
			if (!deleted) {
				throw new IllegalArgumentException("Unable to delete folder: " + storagePath);
			}
		}
		
		// mkdirs creates all folders in the path
		boolean created = storagePathFolder.mkdirs();

		if (!created) {
			throw new IllegalArgumentException("Unable to create folder: "
					+ storagePath);
		}
	}

	// Deletes all files and subdirectories under dir.
    // Returns true if all deletions were successful.
    // If a deletion fails, the method stops attempting to delete and returns false.
    public static boolean deleteDir(File dir) {
        if (dir.isDirectory()) {
            String[] children = dir.list();
            for (int i=0; i<children.length; i++) {
                boolean success = deleteDir(new File(dir, children[i]));
                if (!success) {
                    return false;
                }
            }
        }
    
        // The directory is now empty so delete it
        return dir.delete();
    }
	
	private byte[] readFile(String filePath) throws IOException {
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
				filePath));
		ByteArrayOutputStream baos = new ByteArrayOutputStream();

		byte buff[] = new byte[1024];

		int count = bis.read(buff);

		while (count != -1) {
			baos.write(buff, 0, count);
			count = bis.read(buff);
		}

		bis.close();
		baos.close();

		return baos.toByteArray();
	}

	private void writeFile(File file, byte[] content)
			throws IOException {
		BufferedOutputStream bos = new BufferedOutputStream(
				new FileOutputStream(file));
		bos.write(content);
		bos.close();
	}

	private void createThumbnail(String imgFilePath, String thumbPath,
			int thumbWidth, int thumbHeight) throws Exception {

		Image image = Toolkit.getDefaultToolkit().getImage(imgFilePath);
		MediaTracker mediaTracker = new MediaTracker(new Container());
		mediaTracker.addImage(image, 0);
		mediaTracker.waitForID(0);
		double thumbRatio = (double) thumbWidth / (double) thumbHeight;
		int imageWidth = image.getWidth(null);
		int imageHeight = image.getHeight(null);
		double imageRatio = (double) imageWidth / (double) imageHeight;

		if (thumbRatio < imageRatio) {
			thumbHeight = (int) (thumbWidth / imageRatio);
		} else {
			thumbWidth = (int) (thumbHeight * imageRatio);
		}

		BufferedImage thumbImage = new BufferedImage(thumbWidth, thumbHeight,
				BufferedImage.TYPE_INT_RGB);
		Graphics2D graphics2D = thumbImage.createGraphics();
		graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
				RenderingHints.VALUE_INTERPOLATION_BILINEAR);
		graphics2D.drawImage(image, 0, 0, thumbWidth, thumbHeight, null);
		BufferedOutputStream out = new BufferedOutputStream(
				new FileOutputStream(thumbPath));

		JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
		JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(thumbImage);
		int quality = 100;
		param.setQuality((float) quality / 100.0f, false);
		encoder.setJPEGEncodeParam(param);
		encoder.encode(thumbImage);
		out.close();
	}
	
	private String getThumbPath(String photoPath) {
		// compose the name of the thumbnail given the photo path
		// the last part is the thumb name which is identical with the photo name
		// but starting 'thumb' instead of 'pic'
		int index = photoPath.lastIndexOf(File.separatorChar);
		
		StringBuilder thumbPath = new StringBuilder();
		if (index > 0) {
			thumbPath.append(photoPath.substring(0, index + 1));
			thumbPath.append("thumb" + photoPath.substring(index + 4));
			return thumbPath.toString();
		} else {
			// 
			return "thumb" + photoPath.substring(3);
		}
	}

}
